/*
    DIMVisual-KAAPI, the DIMVisual bundle for KAAPI trace files
    Copyright (c) 2008 Lucas Mello Schnorr <schnorr@gmail.com>

    This file is part of DIMVisual-KAAPI.

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
#include "KAAPIFileReader.h"

@implementation KAAPIFileReader
- (void) searchTicksPerSecond
{
	Util::Record *r;
	GEvent *e;
	GName *name;

	//search in buffer
	unsigned int i;
	for (i = 0; i < [buf count]; i++){
		e = (GEvent *)[buf objectAtIndex: i];
		name = [e name];
		if ([[name description] isEqual: @"EVT_UTIL_PROCESS_INFO"]){
			GFields *f = [e fields];
			ticksPerSecond = [[f fieldWithSimpleStringKey: @"tick_per_s"] doubleValue];
		
			timeOfDayEV = [[f fieldWithSimpleStringKey: @"timeofday"] doubleValue]; 
			tickEV = [[[e timestamp] description] doubleValue];
			break;
		}
	}

	while (ticksPerSecond == 0){ //ok, did not found in buffer
		r = [k read];
		e = [self parseKAAPIEvent: r];
		[buf addObject: e];

		name = [e name];
		if ([[name description] isEqual: @"EVT_UTIL_PROCESS_INFO"]){
			GFields *f = [e fields];
			ticksPerSecond = [[f fieldWithSimpleStringKey: @"tick_per_s"] doubleValue];
		
			timeOfDayEV = [[f fieldWithSimpleStringKey: @"timeofday"] doubleValue]; 
			tickEV = [[[e timestamp] description] doubleValue];
			break;
		}
	}
	if (ticksPerSecond == 0){
		NSString *str = [NSString stringWithFormat: @"KAAPIFileReader (%@): file %@ does not have an event of type Event::EVT_UTIL_PROCESS_INFO (level=%d,event=%d) as expected by the dimvisual-kaapi module.", self, traceFilename, Event::TR_UTIL_LEVEL, Event::UTIL_PROCESS_INFO];
		[[NSException exceptionWithName: @"DIMVisual-KAAPIFileReader" reason: str userInfo: nil] raise];
	}
}

- (void) searchHostnameAndDefineSync
{
	Util::Record *r;
	GEvent *e;

	while (hostname == nil){
		r = [k read];
		e = [self parseKAAPIEvent: r];
		[buf addObject: e];

		GName *n = [e name];
		if ([[n description] isEqual: @"EVT_UTIL_PROCESS_NAME"]){
			int x, i;
			GFields *f = [e fields];
			NSMutableString *h = [NSMutableString string];
			x = [[f fieldWithSimpleStringKey: @"csize"] intValue];
			for (i = 0; i < (x + 31)/32; i++){
				r = [k read];
				GEvent *bloc = [self parseKAAPIEvent: r];
				GFields *blocf = [bloc fields];
				NSString *str;
				str = [blocf fieldWithSimpleStringKey: @"name"];
				[h appendString: str];
				[buf addObject: bloc];
			}
			hostname = h;
			[hostname retain];
			sync = [syncs objectForKey: hostname];
			break;
		}
	}
	if (hostname == nil){
		NSString *str = [NSString stringWithFormat: @"KAAPIFileReader (%@): file %@ does not have an event of type Event::EVT_UTIL_PROCESS_NAME as expected by the dimvisual-kaapi module.", self, traceFilename];
		[[NSException exceptionWithName: @"DIMVisual-KAAPIFileReader" reason: str userInfo: nil] raise];
	}
}

- (void) defineTimestampForEvent: (GEvent *) e
{
	if (ticksPerSecond != 0 && timeOfDayEV != 0 && tickEV != 0){
		double thistick = [[[e timestamp] description] doubleValue];
		double ntev = ((thistick - tickEV)/ticksPerSecond)+timeOfDayEV;
		GTimestamp *t = [[GTimestamp alloc] init];
		[t setTimestamp:[NSString stringWithFormat:@"%f",ntev]];
		[e setTimestamp: t];
		[t release];
	}
}

- (void) defineHostnameForEvent: (GEvent *) e
{
	if (hostname != nil){
		GFields *f = [e fields];
		NSString *value5 = [NSString stringWithFormat: @"%@", hostname];
		[f setFieldWithStringKey: @"hostname" withValue: value5];
	}
}

- (void) synchronizeEvent: (GEvent *) e
{
	if (sync != nil){
		NSString *oldtime = [[e timestamp] description];
		double oldtimed = [oldtime doubleValue];
		oldtimed = oldtimed * 1000000;
		NSString *newtime = [sync correctTime: [NSString stringWithFormat: @"%.0f", oldtimed]];
		double newtimed = [newtime doubleValue];
		newtimed = newtimed / 1000000;
		newtime = [NSString stringWithFormat: @"%f", newtimed];
		GTimestamp *timestamp = [[GTimestamp alloc] init];
		[timestamp setTimestamp: newtime];
		[e setTimestamp: timestamp];
		[timestamp release];
	}
}

/********************************************************/
- (GEvent *) parseKAAPIEvent: (Util::Record *) r
{
	return [super parseKAAPIEvent: r];
}

- (void) setTopEventInit
{
	if (hostname == nil){
		[self searchHostnameAndDefineSync];
	}

	if (ticksPerSecond == 0){
		[self searchTicksPerSecond];
	}

	unsigned int i;
	for (i = 0; i < [buf count]; i++){
		GEvent *e = (GEvent *)[buf objectAtIndex: i];
		[self defineTimestampForEvent: e];
		[self defineHostnameForEvent: e];
		[self synchronizeEvent: e];
	}
}

- (GEvent *) topEvent
{
	GEvent *ret;
	if ([buf count] > 0){
		ret = [buf objectAtIndex: 0];
		[buf removeObjectAtIndex: 0];
	}else{
		Util::Record *r = [k read];
		ret = [self parseKAAPIEvent: r];
		if (ret != nil){
			[self defineTimestampForEvent: ret];
			[self defineHostnameForEvent: ret];
			[self synchronizeEvent: ret];
		}
	}
	return ret;
}


- (id) initWithFileName: (NSString *) traceFile
        andSyncFileName: (NSString *) syncFile
{
	self = [super init];
	NSSet *hosts;
	int i;

	traceFilename = traceFile;
	[traceFilename retain];

	/* loading sync file with synchronization info's */
	syncs = [[NSMutableDictionary alloc] init];
	hosts = [NSSet setWithArray: [Sync allMachinesOfFileNamed: syncFile]];
	for (i = 0; i < (int)[[hosts allObjects] count]; i++){
		Sync *s;
		NSString *host = [[hosts allObjects] objectAtIndex: i];
		s=[[Sync alloc] initWithFileName: syncFile toHostname: host];
		[syncs setObject: s forKey: host];
		[s release];
	}

	/* init */
	k = [[KAAPIRecordReaderObjc alloc] initWithFile: [traceFile cString]];
	if (k == nil){
		NSLog (@"error loading traceFile %@", traceFile);
		return nil;
	}

	ticksPerSecond = 0;
	tickEV = 0;
	timeOfDayEV = 0;

	hostname = nil;
	buf = [[NSMutableArray alloc] init];
	topEvent = nil;
	/* set topEvent */
	[self setTopEventInit];
	topEvent = [self topEvent];
	[topEvent retain];
	NSLog (@"%@, %@", self, [self time]);
        return self;
}


- (GTimestamp *) time
{
	if (topEvent != nil){
		return [topEvent timestamp];
	}else{
		return nil;
	}
}

- (void) dealloc
{
	[super dealloc];
}

- (GEvent *) event
{
	GEvent *ev = topEvent;
	topEvent = [self topEvent];
	[topEvent retain];
	[ev autorelease];
	return ev;
}

- (NSString *) filename;
{
	return traceFilename;
}
@end

